#ifndef __ControllerManager_H__
#define __ControllerManager_H__

#include "U2PreRequest.h"
#include "U2SharedPtr.h"
#include "U2Singleton.h"
#include "U2Common.h"
#include "U2Controller.h"
#include "U2PredefinedControllers.h"
#include "U2TextureUnitState.h"


U2EG_NAMESPACE_BEGIN



typedef U2SharedPtr< ControllerValue<u2real> > ControllerValueRealPtr;
typedef U2SharedPtr< ControllerFunction<u2real> > ControllerFunctionRealPtr;


/** Class for managing Controller instances.
@remarks
    This class is responsible to keeping tabs on all the Controller instances registered
    and updating them when requested. It also provides a number of convenience methods
    for creating commonly used controllers (such as texture animators).
*/
class _U2Share ControllerManager : public U2Singleton<ControllerManager>, public ControllerAlloc
{
protected:
    typedef std::set<Controller<u2real>*> ControllerList;
    ControllerList mControllers;

    /// Global predefined controller
    ControllerValueRealPtr mFrameTimeController;
    
	/// Global predefined controller
	ControllerFunctionRealPtr mPassthroughFunction;

	// Last frame number updated
    unsigned long mLastFrameNumber;

public:
    ControllerManager();
    ~ControllerManager();

    /** Creates a new controller and registers it with the manager.
    */
    Controller<u2real>* createController(const ControllerValueRealPtr& src,
        const ControllerValueRealPtr& dest, const ControllerFunctionRealPtr& func);

    /** Creates a new controller use frame time source and passthrough controller function.
    */
    Controller<u2real>* createFrameTimePassthroughController(
        const ControllerValueRealPtr& dest);

    /** Destroys all the controllers in existence.
    */
    void clearControllers(void);

    /** Updates all the registered controllers.
    */
    void updateAllControllers(void);


    /** Returns a ControllerValue which provides the time since the last frame as a control value source.
    @remarks
        A common source value to use to feed into a controller is the time since the last frame. This method
        returns a pointer to a common source value which provides this information.
    @par
        Remember the value will only be up to date after the RenderSystem::beginFrame method is called.
    @see
        RenderSystem::beginFrame
    */
    const ControllerValueRealPtr& getFrameTimeSource(void) const;

	/** Retrieve a simple passthrough controller function. */
	const ControllerFunctionRealPtr& getPassthroughControllerFunction(void) const;

    /** Creates a texture layer animator controller.
    @remarks
        This helper method creates the Controller, ControllerValue and ControllerFunction classes required
        to animate a texture.
    @param
        layer TextureUnitState object to animate
    @param
        sequenceTime The amount of time in seconds it will take to loop through all the frames.
    */
    Controller<u2real>* createTextureAnimator(TextureUnitState* layer, u2real sequenceTime);

	/** Creates a basic time-based texture uv coordinate modifier designed for creating scrolling textures.
    @remarks
        This simple method allows you to easily create constant-speed uv scrolling textures. If you want to 
		specify different speed values for horizontal and vertical scroll, use the specific methods
		ControllerManager::createTextureUScroller and ControllerManager::createTextureVScroller.
		If you want more control, look up the ControllerManager::createTextureWaveTransformer 
		for more complex wave-based scrollers / stretchers / rotators.
    @param
        layer The texture layer to animate.
    @param
        speed Speed of horizontal (u-coord) and vertical (v-coord) scroll, in complete wraps per second
    */
    Controller<u2real>* createTextureUVScroller(TextureUnitState* layer, u2real speed);

    /** Creates a basic time-based texture u coordinate modifier designed for creating scrolling textures.
    @remarks
        This simple method allows you to easily create constant-speed u scrolling textures. If you want more
        control, look up the ControllerManager::createTextureWaveTransformer for more complex wave-based
        scrollers / stretchers / rotators.
    @param
        layer The texture layer to animate.
    @param
        uSpeed Speed of horizontal (u-coord) scroll, in complete wraps per second
    */
    Controller<u2real>* createTextureUScroller(TextureUnitState* layer, u2real uSpeed);

	/** Creates a basic time-based texture v coordinate modifier designed for creating scrolling textures.
    @remarks
        This simple method allows you to easily create constant-speed v scrolling textures. If you want more
        control, look up the ControllerManager::createTextureWaveTransformer for more complex wave-based
        scrollers / stretchers / rotators.
    @param
        layer The texture layer to animate.            
    @param
        vSpeed Speed of vertical (v-coord) scroll, in complete wraps per second
    */
    Controller<u2real>* createTextureVScroller(TextureUnitState* layer, u2real vSpeed);

    /** Creates a basic time-based texture coordinate modifier designed for creating rotating textures.
    @return
        This simple method allows you to easily create constant-speed rotating textures. If you want more
        control, look up the ControllerManager::createTextureWaveTransformer for more complex wave-based
        scrollers / stretchers / rotators.
    @param
        layer The texture layer to rotate.
    @param
        vSpeed Speed of rotation, in complete anticlockwise revolutions per second
    */
    Controller<u2real>* createTextureRotater(TextureUnitState* layer, u2real speed);

    /** Creates a very flexible time-based texture transformation which can alter the scale, position or
        rotation of a texture based on a wave function.
    @param
        layer The texture layer to affect
    @param
        ttype The type of transform, either translate (scroll), scale (stretch) or rotate (spin)
    @param
        waveType The shape of the wave, see WaveformType enum for details
    @param
        base The base value of the output
    @param
        frequency The speed of the wave in cycles per second
    @param
        phase The offset of the start of the wave, e.g. 0.5 to start half-way through the wave
    @param
        amplitude Scales the output so that instead of lying within 0..1 it lies within 0..1*amplitude for exaggerated effects
    */
    Controller<u2real>* createTextureWaveTransformer(TextureUnitState* layer, TextureUnitState::TextureTransformType ttype,
        WaveformType waveType, u2real base = 0, u2real frequency = 1, u2real phase = 0, u2real amplitude = 1);

    /** Creates a controller for passing a frame time value through to a vertex / fragment program parameter.
    @remarks
        The destination parameter is expected to be a float, and the '.x' attribute will be populated
        with the appropriately scaled time value.
    @param params The parameters to update
    @param paramIndex The index of the parameter to update; if you want a named parameter, then
        retrieve the index beforehand using GpuProgramParameters::getParamIndex
    @param factor The factor by which to adjust the time elapsed by before passing it to the program
    */
    /**********************@@@@@@@@@@@@@@@@@@@@@
    Controller<u2real>* createGpuProgramTimerParam(GpuProgramParametersSharedPtr params, size_t paramIndex,
        u2real timeFactor = 1.0f);
    */

    /** Removes & destroys the controller passed in as a pointer.
    */
    void destroyController(Controller<u2real>* controller);

	/** Return relative speed of time as perceived by time based controllers.
    @remarks
        See setTimeFactor for full information on the meaning of this value.
	*/
	u2real getTimeFactor(void) const;

	/** Set the relative speed to update frame time based controllers.
    @remarks
        Normally any controllers which use time as an input (FrameTimeController) are updated
        automatically in line with the real passage of time. This method allows you to change
        that, so that controllers are told that the time is passing slower or faster than it
        actually is. Use this to globally speed up / slow down the effect of time-based controllers.
    @param tf The virtual speed of time (1.0 is real time).
	*/
	void setTimeFactor(u2real tf);

	/** Gets the constant that is added to time lapsed between each frame.
	@remarks
		See setFrameDelay for full information on the meaning of this value.
	*/
	u2real getFrameDelay(void) const;

	/** Sets a constant frame rate.
	@remarks
		This function is useful when rendering a sequence to
		files that should create a film clip with constant frame
		rate.
		It will ensure that scrolling textures and animations
		move at a constant frame rate.
	@param fd The delay in seconds wanted between each frame 
		(1.0f / 25.0f means a seconds worth of animation is done 
		in 25 frames).
	*/
	void setFrameDelay(u2real fd);

	/** Return the elapsed time.
    @remarks
        See setElapsedTime for full information on the meaning of this value.
    */
    u2real getElapsedTime(void) const;

    /** Set the elapsed time.
    @remarks
        Normally elapsed time accumulated all frames time (which speed relative to time
        factor) since the rendering loop started. This method allows your to change that to
        special time, so some elapsed-time-based globally effect is repeatable.
    @param elapsedTime The new elapsed time
    */
    void setElapsedTime(u2real elapsedTime);

    /** Override standard Singleton retrieval.
    @remarks
        Why do we do this? Well, it's because the Singleton
        implementation is in a .h file, which means it gets compiled
        into anybody who includes it. This is needed for the
        Singleton template to work, but we actually only want it
        compiled into the implementation of the class based on the
        Singleton, not all of them. If we don't change this, we get
        link errors when trying to use the Singleton-based class from
        an outside dll.
    @par
        This method just delegates to the template version anyway,
        but the implementation stays in this single compilation unit,
        preventing link errors.
    */
    static ControllerManager& getSingleton(void);

    /** Override standard Singleton retrieval.
    @remarks
        Why do we do this? Well, it's because the Singleton
        implementation is in a .h file, which means it gets compiled
        into anybody who includes it. This is needed for the
        Singleton template to work, but we actually only want it
        compiled into the implementation of the class based on the
        Singleton, not all of them. If we don't change this, we get
        link errors when trying to use the Singleton-based class from
        an outside dll.
    @par
        This method just delegates to the template version anyway,
        but the implementation stays in this single compilation unit,
        preventing link errors.
    */
    static ControllerManager* getSingletonPtr(void);
};


U2EG_NAMESPACE_END


#endif
